App.require(["canvasTool", "htmlTool"], function (canvasTool, htmlTool) {
    var app = App.getCurrent();

    app.defineLayer("str-scatter-chart", {
        render: function (next) {
            this.initProperty();
            this.data.isChange = true;
            this.data.isMouseIn = false;
            this.fetch("./index.html", function (text) {
                next(this.renderHTML(text));
            });
        },
        dispose: function () {
            this.removeAnimation();
            this.data.isChange = true;
            this.data.isMouseIn = false;
        },
        removeOption: function (index) {
            this.data.options.splice(index, 1);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        appendOption: function (option) {
            this.data.options.push(option);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        insertBefore: function (index, option) {
            this.data.options.splice(index, 0, option);
            this.data.isChange = true;
            var property = this.property;
            if (property.animation) this.addPropertyAnimation(property.animation, this);
            else this.addChange();
        },
        changeOption: function (index, opt) {
            var option = this.data.options[index];
            if (!option) return;
            this.data.isChange = true;
            this.addChange(opt, option);
        },
        get x() {
            return this.getValue("x");
        },
        set x(value) {
            this.setValue("x", value);
        },
        get fill() {
            return this.getValue("fill");
        },
        set fill(value) {
            this.setValue("fill", value)
        },
        get stroke() {
            return this.getValue("stroke");
        },
        set stroke(value) {
            this.setValue("stroke", value)
        },
        get y() {
            return this.getValue("y");
        },
        set y(value) {
            this.setValue("y", value)
        },
        set height(value) {
            this.setValue("height", value);
        },
        get height() {
            return this.getValue("height");
        },
        set width(value) {
            this.setValue("width", value);
        },
        get width() {
            return this.getValue("width");
        },
        get transform() {
            return this.getValue("transform");
        },
        set transform(value) {
            this.setValue("transform", value);
        },
        get shadow() {
            return this.getValue("shadow");
        },
        set shadow(value) {
            this.setValue("shadow", value);
        },
        get hidden() {
            return this.getValue("hidden");
        },
        set hidden(value) {
            this.setValue("hidden", value);
        },
        get percent() {
            return this.getValue("percent");
        },
        set percent(value) {
            this.setValue("percent", value)
        },
        get animation() {
            return this.getValue("animation");
        },
        set animation(value) {
            if (this.setValue("animation", value)) {
                if (value) this.addPropertyAnimation(value, this);
            }
        },
        set transition(value) {
            this.setValue("transition", value);
        },
        get transition() {
            return this.getValue("transition");
        },
        set opacity(value) {
            this.setValue("opacity", value);
        },
        get opacity() {
            return this.getValue("opacity");
        },
        get direction() {
            return this.getValue("direction");
        },
        set direction(value) {
            this.setValue("direction", value);
        },
        get offset() {
            return this.getValue("offset");
        },
        set offset(value) {
            this.setValue("offset", value);
        },
        get marker() {
            return this.getValue("marker");
        },
        set marker(value) {
            this.setValue("marker", value);
        },
        initProperty: function () {
            var property = this.property;

            this.data.attributeStr = this._createPropertyStr(property);
            this.data.options = htmlTool.getOptions(this.slot);

            if (property.animation) this.addPropertyAnimation(property.animation, this);
            this._offset = { x: 0, y: 0 };
        },
        transformView: function (ctx, ratio) {
            
            if (this.transform) {
                var tList = canvasTool.createTransformList(this.transform, ratio);
                for (var i = 0; i < tList.length; i++) {
                    var tObj = tList[i];
                    ctx[tObj.action].apply(ctx, tObj.args);
                }
            }
        },
        moveLayerHandler: function (ev, ctx, ratio) {
            var obj = this.containsBounds(ctx, ev.clientX, ev.clientY, ratio);
            if (obj) {
                if (!this.data.isMouseIn) {
                    this.data.isMouseIn = true;
                    this.data.tempIndex = obj.index;
                    this.data.tempOption = obj.option;
                    this.dispatchCustomEvent("scatterchartmouseenter", {
                        component: this,
                        event: ev,
                        index: obj.index,
                        obj: obj.option
                    });
                }
            } else {
                if (this.data.isMouseIn) {
                    this.data.isMouseIn = false;
                    this.dispatchCustomEvent("scatterchartmouseleave", {
                        component: this,
                        event: ev,
                        index: this.data.tempIndex,
                        obj: this.data.tempOption
                    });
                    this.data.tempOption = null;
                    this.data.tempIndex = null;
                }
            }
        },
        clickLayerHandler: function (ev, ctx, ratio) {
            var obj = this.containsBounds(ctx, ev.clientX, ev.clientY, ratio);
            if (obj) {
                this.dispatchCustomEvent("scatterchartclick", {
                    component: this,
                    event: ev,
                    index: obj.index,
                    data: obj.option
                });
            }
        },
        containsBounds: function (ctx, x, y, ratio) {
            ctx.save();
            var options = this.data.options,
                isIn = false;
            ctx.translate(this.x * ratio, this.y * ratio);
            this.transformView(ctx, ratio);
            var offsetObj = canvasTool.createOffsetObj(this.offset, ratio), direction = this.direction;
            var startObj = this._getStartPos(offsetObj, direction, ratio),
                percent = this.percent;
            var startX = startObj.x,
                startY = startObj.y;

            for (var i = 0; i < options.length; i++) {
                var obj = options[i], h = parseFloat(obj.value) * ratio * percent;
                var marker = this.getMarkerByStr(obj.marker || this.marker) || this.getDefaultMarker(ratio);
                ctx.save();
                var offsetPos = this._getOffsetPos(startX, startY, parseFloat(obj.offset) * ratio, direction);
                var pos = this._createPoints(offsetPos, h, direction);
                ctx.translate(pos.x + marker.offsetX, pos.y + marker.offsetY);
                isIn = marker.isPointInPath(ctx, x, y, ratio, obj);
                ctx.restore();
                if (isIn) break;
            }
            ctx.restore();
            if (i < options.length) {
                return {
                    index: i,
                    option: options[i]
                }
            }
            return null;
        },
        _createPoints: function (pos, h, direction) {
            var point = {
                x: pos.x,
                y: pos.y
            };
            switch (direction) {
                case "row":
                    point.y = pos.y - h;
                    break;
                case "row-reverse":
                    point.y = pos.y + h;
                    break;
                case "column":
                    point.x = pos.x + h;
                    break;
                case "column-reverse":
                    point.x = pos.x - h;
                    break;
            }
            return point;
        },
        drawSelf: function (ctx, ratio) {
            var property = this.property,
                options = this.data.options;
            var dObj = this.getPropertyUse(["opacity", "percent", "x", "y", "fill", "stroke", "offset", "shadow", "width", "height"]);
            if (typeof dObj.opacity !== "undefined") ctx.globalAlpha = parseFloat(dObj.opacity);
            if (this.hidden || options.length == 0) return;
            ctx.translate(dObj.x * ratio, dObj.y * ratio);
            this.transformView(ctx, ratio);
            var keyToCanvas = canvasTool.keyToCanvas;
            for (var key in property) {
                var ctxKey = keyToCanvas[key];
                if (ctxKey) {
                    if (ctxKey == "fillStyle" || ctxKey == "strokeStyle") continue;
                    else ctx[ctxKey] = this[key];
                }
            }

            var offsetObj = this.createOffsetObj(dObj.offset, ratio, this._offset);
            var direction = this.direction;
            var startObj = this._getStartPos(offsetObj, direction, ratio),
                percent = dObj.percent;
            var startX = startObj.x,
                startY = startObj.y,
                options = this.data.options;
            for (var i = 0; i < options.length; i++) {
                var obj = options[i],
                    h = parseFloat(obj.value) * ratio * percent;
                var offsetPos = this._getOffsetPos(startX, startY, parseFloat(obj.offset) * ratio, direction);
                var pos = this._createPoints(offsetPos, h, direction);
                var marker = this.getMarkerByStr(obj.marker || this.marker) || this.getDefaultMarker(ratio);
                ctx.save();
                ctx.translate(pos.x + marker.offsetX, pos.y + marker.offsetY);
                if (dObj.shadow) this.useShadow(ctx, obj.shadow || dObj.shadow, ratio);
                obj.fill = obj.fill || dObj.fill;
                obj.stroke = obj.stroke || dObj.stroke;
                marker.drawToCanvas(ctx, ratio, obj);
                ctx.restore();
            }
        },
        _getStartPos: function (offsetObj, direction, ratio) {
            switch (direction) {
                case "row":
                    return {
                        x: offsetObj.x,
                            y: this.height * ratio - offsetObj.y
                    };
                case "row-reverse":
                case "column":
                    return {
                        x: offsetObj.x,
                            y: offsetObj.y
                    };
                case "column-reverse":
                    return {
                        x: -offsetObj.x + this.width * ratio,
                            y: offsetObj.y
                    };
            }
        },
        _getOffsetPos: function (startX, startY, offset, direction) {
            switch (direction) {
                case "row":
                case "row-reverse":
                    return {
                        x: startX + offset, y: startY
                    };
                case "column":
                case "column-reverse":
                    return {
                        x: startX, y: startY + offset
                    }
            }
        },
        getDefaultMarker: function (ratio) {
            var that = this;
            return {
                offsetX: -10 * ratio,
                offsetY: -10 * ratio,
                isPointInPath: function (ctx, x, y, ratio, obj) {
                    var r = typeof obj.r === "undefined" ? 8 : parseFloat(obj.r);
                    ctx.beginPath();
                    ctx.moveTo(10 * ratio, 10 * ratio);
                    ctx.arc(10 * ratio, 10 * ratio, r * ratio, 0, Math.PI * 2, false);
                    return ctx.isPointInPath(x * ratio, y * ratio);
                },
                drawToCanvas: function (ctx, ratio, obj) {
                    var r = typeof obj.r === "undefined" ? 8 : parseFloat(obj.r);
                    ctx.beginPath();
                    ctx.arc(10 * ratio, 10 * ratio, r * ratio, 0, Math.PI * 2, false);
                    if (obj.fill) {
                        ctx.fillStyle = that.getFillOrStrokeStyle(obj.fill);
                        ctx.fill();
                    }
                    if (obj.stroke) {
                        ctx.strokeStyle = that.getFillOrStrokeStyle(obj.stroke);
                        ctx.stroke();
                    }
                }
            }
        },

    })
})